using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace SIM_TPN_6
{
    public partial class frmPrincipal : Form
    {
        List<double[]> calcC1;
        List<double[]> calcC2;
        List<double[]> calcC3;
        private static int MAX_ITERACIONES = 10000;

        public frmPrincipal()
        {
            InitializeComponent();
            this.lblCantIter.Text = "Iteraciones: " + this.dgvDatos.Rows.Count.ToString();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            dgvDatos.Height = this.Height - dgvDatos.Top - 50;
            dgvDatos.Width = this.Width - dgvDatos.Left - 30;
        }

        private void Calcular(String metodo)
        {
            //double paramH = Double.Parse(this.txtParamH.Text);
            double paramH = Double.Parse(this.numParamH.Text);
            double paramC1 = Double.Parse(this.txtParamC1.Text);
            double paramC2 = Double.Parse(this.txtParamC2.Text);
            double paramC3 = Double.Parse(this.txtParamC3.Text);
            double paramX1 = Double.Parse(this.txtParamX1.Text);
            double paramX2 = Double.Parse(this.txtParamX2.Text);
            double limiteX1 = 0.005;
            double limiteX2 = 0.01;
            
            calcC1 = new List<double[]>();
            calcC2 = new List<double[]>();
            calcC3 = new List<double[]>();

            switch (metodo)
            {
                case "E":
                    calcC1 = CalcularEuler(paramH, paramC1, paramX1, paramX2, limiteX1, limiteX2);
                    calcC2 = CalcularEuler(paramH, paramC2, paramX1, paramX2, limiteX1, limiteX2);
                    calcC3 = CalcularEuler(paramH, paramC3, paramX1, paramX2, limiteX1, limiteX2);
                    break;
                case "RK":
                    calcC1 = CalcularRungeKutta(paramH, paramC1, paramX1, paramX2, limiteX1, limiteX2);
                    calcC2 = CalcularRungeKutta(paramH, paramC2, paramX1, paramX2, limiteX1, limiteX2);
                    calcC3 = CalcularRungeKutta(paramH, paramC3, paramX1, paramX2, limiteX1, limiteX2);
                    break;
                default:
                    break;
            }
            LlenarGrilla(calcC1, calcC2, calcC3);
        }

        private List<double[]> CalcularEuler(double h, double c, double x1, double x2, 
                                            double x1Corte, double x2Corte)
        {
            List<double[]> calc = new List<double[]>();
            double[] linea = new double[3];
            int CONTADOR_AUXILIAR = 1;

            linea[0] = h;
            linea[1] = x1;
            linea[2] = x2;

            calc.Add(new double[] { linea[0], linea[1], linea[2] });

            while (degToRad(Math.Abs(linea[1])) > x1Corte || degToRad(Math.Abs(linea[2])) > x2Corte)
            {
                linea[0] = linea[0] + h;
                linea[1] = linea[1] + h * linea[2];
                linea[2] = linea[2] + h * (-2 * Math.Sin(degToRad(linea[1])) - Math.Sign(c * linea[1] + linea[2]));

                calc.Add(new double[] { linea[0], linea[1], linea[2] });

                CONTADOR_AUXILIAR++;
                if (CONTADOR_AUXILIAR >= MAX_ITERACIONES) break;
            }

            //calc.Add(linea);
            return calc;
        }

        private List<double[]> CalcularRungeKutta(double h, double c, double x1, double x2,
                                           double x1Corte, double x2Corte)
        {
            List<double[]> calc = new List<double[]>();
            double[] linea = new double[3];
            int CONTADOR_AUXILIAR = 1;

            linea[0] = h;
            linea[1] = x1;
            linea[2] = x2;

            double k11 = 0;
            double k21 = 0;
            double k31 = 0;
            double k41 = 0;
            double k12 = 0;
            double k22 = 0;
            double k32 = 0;
            double k42 = 0;

            calc.Add(new double[] { linea[0], linea[1], linea[2] });

            while (degToRad(Math.Abs(linea[1])) > x1Corte || degToRad(Math.Abs(linea[2])) > x2Corte)
            {
                k11 = h * linea[2];
                k21 = h * (linea[2] + 0.5 * k11);
                k31 = h * (linea[2] + 0.5 * k21);
                k41 = h * (linea[2] + k31);

                k12 = h * (-2 * Math.Sin(degToRad(linea[1])) - Math.Sign(c * linea[1] + linea[2]));
                k22 = h * (-2 * Math.Sin(degToRad(linea[1] + 0.5 * h)) - Math.Sign(c * (linea[1] + 0.5 * h) + (linea[2] + 0.5 * k12)));
                k32 = h * (-2 * Math.Sin(degToRad(linea[1] + 0.5 * h)) - Math.Sign(c * (linea[1] + 0.5 * h) + (linea[2] + 0.5 * k22)));
                k42 = h * (-2 * Math.Sin(degToRad(linea[1] + h)) - Math.Sign(c * (linea[1] + h) + (linea[2] + k32)));



                linea[0] = linea[0] + h;
                linea[1] = linea[1] + ((double)1 / (double)6) * (k11 + 2 * k21 + 2 * k31 + k41);
                linea[2] = linea[2] + ((double)1 / (double)6) * (k12 + 2 * k22 + 2 * k32 + k42);

                calc.Add(new double[] { linea[0], linea[1], linea[2] });

                CONTADOR_AUXILIAR++;
                if (CONTADOR_AUXILIAR >= MAX_ITERACIONES) break;
            }

            //calc.Add(linea);
            return calc;
        }

        private void LlenarGrilla(List<double[]> listaC1, List<double[]> listaC2, List<double[]> listaC3)
        {
            int cont = 0;
            this.dgvDatos.Rows.Clear();
            double MaxTC1 = 0, MaxTC2 = 0, MaxTC3 = 0;


            foreach (double[] lista in listaC1)
            {
                this.dgvDatos.Rows.Add(Math.Round(lista[0],4), Math.Round(lista[1],4), Math.Round(lista[2],4));
                MaxTC1 = lista[0];
            }
            
            foreach (double[] lista in listaC2)
            {
                if (cont >= dgvDatos.Rows.Count)
                {
                    this.dgvDatos.Rows.Add(Math.Round(lista[0], 4), "", "", Math.Round(lista[1], 4), Math.Round(lista[2], 4), "", "");
                }
                else
                {
                    this.dgvDatos.Rows[cont].Cells[3].Value = Math.Round(lista[1], 4).ToString();
                    this.dgvDatos.Rows[cont].Cells[4].Value = Math.Round(lista[2], 4).ToString();
                }
                MaxTC2 = lista[0];
                cont++;
            }
            
            cont = 0;
            foreach (double[] lista in listaC3)
            {
                if (cont >= dgvDatos.Rows.Count)
                {
                    this.dgvDatos.Rows.Add(Math.Round(lista[0], 4), "", "", "", "", Math.Round(lista[1], 4), Math.Round(lista[2], 4));
                }
                else
                {
                    this.dgvDatos.Rows[cont].Cells[5].Value = Math.Round(lista[1], 4).ToString();
                    this.dgvDatos.Rows[cont].Cells[6].Value = Math.Round(lista[2], 4).ToString();
                }
                MaxTC3 = lista[0];
                cont++;
            }

            this.lblCantIter.Text = "Iteraciones: " + this.dgvDatos.Rows.Count.ToString();
            this.lblTmpC1.Text = "Optimo con C1 alcanzado con " + listaC1.Count.ToString();
            this.lblTmpC1.Text += " iteraciones y con t = " + Math.Round(MaxTC1, 2).ToString();
            this.lblTmpC2.Text = "Optimo con C2 alcanzado con " + listaC2.Count.ToString();
            this.lblTmpC2.Text += " iteraciones y con t = " + Math.Round(MaxTC2,2).ToString();
            this.lblTmpC3.Text = "Optimo con C3 alcanzado con " + listaC3.Count.ToString();
            this.lblTmpC3.Text += " iteraciones y con t = " + Math.Round(MaxTC3,2).ToString();
        }

        private double radToDeg(double rad)
        {
            return rad * (180 / Math.PI);
        }

        private double degToRad(double deg)
        {
            return deg * (Math.PI / 180);
        }

        private void Graficar(String tipo)
        {
            frmGrafico fg = new frmGrafico(tipo, this.calcC1, this.calcC2, this.calcC3);
            fg.Show();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void txtParamH_TextChanged(object sender, EventArgs e)
        {

        }

        private void groupBox2_Enter(object sender, EventArgs e)
        {

        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void btnGraficar_Click(object sender, EventArgs e)
        {
            string tipo = "";

            if( this.radGraTX1.Checked == true) tipo = "tx1";
            if (this.radGraTX2.Checked == true) tipo = "tx2";
            if (this.radGraX1X2.Checked == true) tipo = "x1x2";

            Graficar(tipo);
        }

        private void btnCalcular_Click(object sender, EventArgs e)
        {
            String metodo = "";
            if (radEuler.Checked == true) metodo = "E";
            if (this.radRungeKutta.Checked == true) metodo = "RK";
            Calcular(metodo);
            this.btnGraficar.Enabled = true;
        }
    }
}